home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 11 / Mac Magazin and MacEasy Magazine CD - Issue 11.iso / Sharewarebibliothek / Entwickler / ThreadLibrary-1.0 / Source / Libraries / ThreadLibraryManager.c < prev    next >
Text File  |  1995-05-04  |  12KB  |  550 lines

  1. /* See the file Distribution for distribution terms.
  2.     Copyright (c) 1994-1995 Ari Halberstadt */
  3.  
  4. /*    This file contains an interface to Thread Library that simulates Apple's
  5.     Thread Manager. This interface allows you to easily switch between Apple's
  6.     Thread Manager and my Thread Library. All routines and actions supported
  7.     by Apple's Thread Manager, version 2.0, are supported by the routines in
  8.     this library, with the exception of preemptive threads and thread pools.
  9.     Operations on preemptive threads result in no-ops, and attempting to create
  10.     a preemptive threads results in a threadProtocolErr, just as it would
  11.     for the PowerPC version of Thread Manager. Since preemptive threads
  12.     are not supported, thread pools are less important. Threads are always
  13.     created using NewPtr and disposed of using DisposePtr; requests to
  14.     create a thread from a pool, or to recycle a thread when it is
  15.     disposed of, are ignored.
  16.     
  17.     The routines in this library have same the syntax as Thread Manager
  18.     routines, and the names of the routines are the same except for the
  19.     prefix "TLM". Thus, to create a new thread you would use TLMNewThread
  20.     instead of NewThread.
  21.     
  22.     Warning: I have not tested every routine in this file. Use at your own risk. */
  23.  
  24. #include <OSUtils.h>
  25. #include "ThreadLibrary.h"
  26. #include "ThreadLibraryManager.h"
  27.  
  28. static struct {
  29.     ThreadSchedulerProcPtr threadScheduler;
  30.     DebuggerNewThreadProcPtr notifyNewThread;
  31.     DebuggerDisposeThreadProcPtr notifyDisposeThread;
  32.     DebuggerThreadSchedulerProcPtr notifyThreadScheduler;
  33. } gThread;
  34.  
  35. typedef struct {
  36.     ThreadType sn;
  37.     ThreadID id;
  38.     
  39.     ThreadEntryProcPtr entry;
  40.     void *entryParam;
  41.     void **entryResult;
  42.     
  43.     ThreadSwitchProcPtr switcherIn;
  44.     void *switcherInParam;
  45.     
  46.     ThreadSwitchProcPtr switcherOut;
  47.     void *switcherOutParam;
  48.     
  49.     ThreadTerminationProcPtr terminator;
  50.     void *terminatorParam;
  51.     
  52.     long critical;
  53. } ThreadManagerType;
  54.  
  55. static OSErr ThreadIDToSN(ThreadID id, ThreadType *sn)
  56. {
  57.     switch (id) {
  58.     case kNoThreadID:
  59.         *sn = THREAD_NONE;
  60.         break;
  61.     case kCurrentThreadID:
  62.         *sn = ThreadActive();
  63.         break;
  64.     case kApplicationThreadID:
  65.         *sn = ThreadMain();
  66.         break;
  67.     default:
  68.         *sn = id - 2;
  69.         break;
  70.     }
  71.     return(noErr);
  72. }
  73.  
  74. static OSErr ThreadSNToID(ThreadType sn, ThreadID *id)
  75. {
  76.     *id = sn + 2;
  77.     return(noErr);
  78. }
  79.  
  80. static OSErr ThreadSNToPtr(ThreadType sn, void **p)
  81. {
  82.     *p = ThreadData(sn);
  83.     return(ThreadError());
  84. }
  85.  
  86. static OSErr ThreadIDToPtr(ThreadID id, void **p)
  87. {
  88.     ThreadType sn;
  89.     OSErr err;
  90.     
  91.     err = ThreadIDToSN(id, &sn);
  92.     if (! err)
  93.         err = ThreadSNToPtr(sn, p);
  94.     return(err);
  95. }
  96.  
  97. static ThreadType thread_scheduler(ThreadType suggested)
  98. {
  99.     SchedulerInfoRec info;
  100.     ThreadType active;
  101.     OSErr err;
  102.     
  103.     if (gThread.threadScheduler) {
  104.         info.InfoRecSize = sizeof(SchedulerInfoRec);
  105.         info.InterruptedCoopThreadID = kNoThreadID;
  106.         active = ThreadActive();
  107.         err = ThreadError();
  108.         if (! err) {
  109.             err = ThreadSNToID(active, &info.CurrentThreadID);
  110.             if (! err) {
  111.                 err = ThreadSNToID(suggested, &info.SuggestedThreadID);
  112.                 if (! err) {
  113.                     info.SuggestedThreadID = gThread.threadScheduler(&info);
  114.                     if (gThread.notifyThreadScheduler)
  115.                         info.SuggestedThreadID = gThread.notifyThreadScheduler(&info);
  116.                     err = ThreadIDToSN(info.SuggestedThreadID, &suggested);
  117.                 }
  118.             }
  119.         }
  120.         if (err)
  121.             suggested = THREAD_NONE;
  122.     }
  123.     return(suggested);
  124. }
  125.  
  126. static void thread_begin(ThreadType sn, void *data)
  127. {
  128.     ThreadManagerType *thread = data;
  129.     
  130.     if (gThread.notifyNewThread)
  131.         gThread.notifyNewThread(thread->id);
  132. }
  133.  
  134. static void thread_end(ThreadType sn, void *data)
  135. {
  136.     ThreadManagerType *thread = data;
  137.     
  138.     if (thread->terminator)
  139.         thread->terminator(thread->id, thread->terminatorParam);
  140.     if (gThread.notifyDisposeThread)
  141.         gThread.notifyDisposeThread(thread->id);
  142. }
  143.  
  144. static void thread_suspend(void *data)
  145. {
  146.     ThreadManagerType *thread = data;
  147.     
  148.     if (thread->switcherOut)
  149.         thread->switcherOut(thread->id, thread->switcherOutParam);
  150. }
  151.  
  152. static void thread_resume(void *data)
  153. {
  154.     ThreadManagerType *thread = data;
  155.     
  156.     if (thread->switcherIn)
  157.         thread->switcherIn(thread->id, thread->switcherInParam);
  158. }
  159.  
  160. static void thread_entry(void *data)
  161. {
  162.     ThreadManagerType *thread = data;
  163.     void *result;
  164.     
  165.     if (thread->entry) {
  166.         result = thread->entry(thread->entryParam);
  167.         if (thread->entryResult)
  168.             *thread->entryResult = result;
  169.     }
  170. }
  171.  
  172. OSErr TLMCreateThreadPool(ThreadStyle style, short count, Size stack)
  173. {
  174.     return(noErr);
  175. }
  176.  
  177. OSErr TLMGetFreeThreadCount(ThreadStyle style, short *count)
  178. {
  179.     *count = 0;
  180.     return(noErr);
  181. }
  182.  
  183. OSErr TLMGetSpecificThreadCount(ThreadStyle style, Size stack, short *count)
  184. {
  185.     *count = 0;
  186.     return(noErr);
  187. }
  188.  
  189. OSErr TLMGetDefaultThreadStackSize(ThreadStyle style, Size *size)
  190. {
  191.     *size = ThreadStackDefault();
  192.     return(ThreadError());
  193. }
  194.  
  195. OSErr TLMThreadCurrentStackSpace(ThreadID id, long *free)
  196. {
  197.     ThreadType sn;
  198.     OSErr err;
  199.     
  200.     err = ThreadIDToSN(id, &sn);
  201.     if (! err) {
  202.         *free = ThreadStackSpace(sn);
  203.         err = ThreadError();
  204.     }
  205.     return(err);
  206. }
  207.  
  208. OSErr TLMNewThread(ThreadStyle style,
  209.     ThreadEntryProcPtr entry,
  210.     void *param,
  211.     Size stack,
  212.     ThreadOptions options,
  213.     void **result,
  214.     ThreadID *id)
  215. {
  216.     ThreadManagerType *thread;
  217.     ThreadType main;
  218.     OSErr err;
  219.     
  220.     err = noErr;
  221.     thread = NULL;
  222.     if (style == kPreemptiveThread)
  223.         err = threadProtocolErr;
  224.     if (! err) {
  225.     
  226.         /* check if main thread exists */
  227.         main = ThreadMain();
  228.         err = ThreadError();
  229.         if (! err && main == THREAD_NONE) {
  230.  
  231.             /* create main thread */
  232.             thread = (ThreadManagerType *) NewPtrClear(sizeof(ThreadManagerType));
  233.             if (! thread)
  234.                 err = (MemError() ? MemError() : memFullErr);
  235.             if (! err) {
  236.                 thread->sn = ThreadBeginMain(NULL, NULL, thread);
  237.                 err = ThreadError();
  238.             }
  239.             if (err)
  240.                 DisposePtr((Ptr) thread);
  241.         }
  242.         if (! err) {
  243.         
  244.             /* allocate thread structure */
  245.             thread = (ThreadManagerType *) NewPtrClear(sizeof(ThreadManagerType));
  246.             if (! thread)
  247.                 err = (MemError() ? MemError() : memFullErr);
  248.             if (! err) {
  249.             
  250.                 /* allocate thread */
  251.                 thread->entry = entry;
  252.                 thread->entryParam = param;
  253.                 thread->entryResult = result;
  254.                 thread->sn = ThreadBegin(thread_entry, NULL, NULL, thread, stack);
  255.                 err = ThreadError();
  256.                 if (! err) {
  257.                 
  258.                     /* initialize thread */
  259.                     ThreadProcBeginSet(thread->sn, thread_begin);
  260.                     err = ThreadError();
  261.                     if (! err) {
  262.                         ThreadProcEndSet(thread->sn, thread_end);
  263.                         err = ThreadError();
  264.                         if (! err) {
  265.                             err = ThreadSNToID(thread->sn, &thread->id);
  266.                             if (! err) {
  267.                                 if ((options & kNewSuspend) != 0) {
  268.                                     ThreadEnabledSet(thread->sn, false);
  269.                                     err = ThreadError();
  270.                                 }
  271.                             }
  272.                         }
  273.                     }
  274.                     if (err) {
  275.                         ThreadEnd(thread->sn);
  276.                         thread->sn = THREAD_NONE;
  277.                     }
  278.                 }
  279.                 if (err) {
  280.                     DisposePtr((Ptr) thread);
  281.                     thread = NULL;
  282.                 }
  283.             }
  284.         }
  285.     }
  286.     *id = (thread ? thread->id : kNoThreadID);
  287.     return(err);
  288. }
  289.  
  290. OSErr TLMDisposeThread(ThreadID id, void *result, Boolean recycle)
  291. {
  292.     ThreadManagerType *thread;
  293.     ThreadType sn;
  294.     OSErr err;
  295.     
  296.     err = noErr;
  297.     if (id != kNoThreadID) {
  298.         err = ThreadIDToSN(id, &sn);
  299.         if (! err) {
  300.             thread = ThreadData(sn);
  301.             err = ThreadError();
  302.             if (! err) {
  303.                 if (thread->entryResult)
  304.                     *thread->entryResult = result;
  305.                 ThreadEnd(sn);
  306.                 err = ThreadError();
  307.                 if (! err)
  308.                     DisposePtr((Ptr) thread);
  309.             }
  310.         }
  311.     }
  312.     return(err);
  313. }
  314.  
  315. OSErr TLMGetCurrentThread(ThreadID *id)
  316. {
  317.     ThreadType sn;
  318.     OSErr err;
  319.  
  320.     sn = ThreadActive();
  321.     err = ThreadError();
  322.     if (! err)
  323.         err = ThreadSNToID(sn, id);
  324.     return(err);
  325. }
  326.  
  327. OSErr TLMYieldToAnyThread(void)
  328. {
  329.     if (ThreadMain() != THREAD_NONE)
  330.         ThreadYield(0);
  331.     return(ThreadError());
  332. }
  333.  
  334. OSErr TLMThreadBeginCritical(void)
  335. {
  336.     ThreadManagerType *thread;
  337.     ThreadType sn;
  338.     OSErr err;
  339.     
  340.     sn = ThreadActive();
  341.     err = ThreadError();
  342.     if (! err) {
  343.         thread = ThreadData(sn);
  344.         err = ThreadError();
  345.         if (! err) {
  346.             if (thread->critical == LONG_MAX)
  347.                 err = threadProtocolErr;
  348.             if (! err)
  349.                 thread->critical++;
  350.         }
  351.     }
  352.     return(err);
  353. }
  354.  
  355. OSErr TLMThreadEndCritical(void)
  356. {
  357.     ThreadManagerType *thread;
  358.     ThreadType sn;
  359.     OSErr err;
  360.     
  361.     sn = ThreadActive();
  362.     err = ThreadError();
  363.     if (! err) {
  364.         thread = ThreadData(sn);
  365.         err = ThreadError();
  366.         if (! err) {
  367.             if (thread->critical == 0)
  368.                 err = threadProtocolErr;
  369.             if (! err)
  370.                 thread->critical--;
  371.         }
  372.     }
  373.     return(err);
  374. }
  375.  
  376. OSErr TLMYieldToThread(ThreadID id)
  377. {
  378.     ThreadType sn;
  379.     OSErr err;
  380.  
  381.     err = ThreadIDToSN(id, &sn);
  382.     if (! err) {
  383.         ThreadActivate(sn);
  384.         err = ThreadError();
  385.     }
  386.     return(err);
  387. }
  388.  
  389. OSErr TLMGetThreadState(ThreadID id, ThreadState *state)
  390. {
  391.     ThreadType sn;
  392.     OSErr err;
  393.     
  394.     err = ThreadIDToSN(id, &sn);
  395.     if (! err) {
  396.         if (sn == ThreadActive())
  397.             *state = kRunningThreadState;
  398.         else if (! ThreadEnabled(sn))
  399.             *state = kStoppedThreadState;
  400.         else
  401.             *state = kReadyThreadState;
  402.     }
  403.     return(ThreadError());
  404. }
  405.  
  406. OSErr TLMSetThreadState(ThreadID id, ThreadState state, ThreadID suggested)
  407. {
  408.     ThreadType active;
  409.     ThreadType main;
  410.     ThreadType sn;
  411.     OSErr err;
  412.     
  413.     main = ThreadMain();
  414.     err = ThreadError();
  415.     if (! err) {
  416.         active = ThreadActive();
  417.         err = ThreadError();
  418.         if (! err) {
  419.             err = ThreadIDToSN(id, &sn);
  420.             if (! err) {
  421.                 switch (state) {
  422.                 case kRunningThreadState:
  423.                     if (sn != active) {
  424.                         ThreadActivate(sn);
  425.                         err = ThreadError();
  426.                     }
  427.                     break;
  428.                 case kStoppedThreadState:
  429.                     if (sn == main)
  430.                         err = threadProtocolErr;
  431.                     if (! err) {
  432.                         ThreadEnabledSet(sn, false);
  433.                         err = ThreadError();
  434.                         if (! err) {
  435.                             if (sn == active)
  436.                                 ThreadActivate(suggested);
  437.                         }
  438.                     }
  439.                     break;
  440.                 case kReadyThreadState:
  441.                     if (sn == main)
  442.                         err = threadProtocolErr;
  443.                     if (! err) {
  444.                         ThreadEnabledSet(sn, true);
  445.                         err = ThreadError();
  446.                         if (! err) {
  447.                             if (sn == active)
  448.                                 ThreadActivate(suggested);
  449.                         }
  450.                     }
  451.                     break;
  452.                 default:
  453.                     err = threadProtocolErr;
  454.                     break;
  455.                 }
  456.             }
  457.         }
  458.     }
  459.     return(err);
  460. }
  461.  
  462. OSErr TLMSetThreadStateEndCritical(ThreadID id, ThreadState state, ThreadID suggested)
  463. {
  464.     OSErr err;
  465.  
  466.     err = TLMThreadEndCritical();
  467.     if (! err)
  468.         err = TLMSetThreadState(id, state, suggested);
  469.     return(err);
  470. }
  471.  
  472. OSErr TLMGetThreadCurrentTaskRef(ThreadTaskRef *task)
  473. {
  474.     *task = (ThreadTaskRef) SetCurrentA5();
  475.     return(noErr);
  476. }
  477.  
  478. OSErr TLMGetThreadStateGivenTaskRef(ThreadTaskRef task, ThreadID id, ThreadState *state)
  479. {
  480.     long oldA5;
  481.     OSErr err;
  482.  
  483.     oldA5 = SetA5((long) task);
  484.     err = TLMGetThreadState(id, state);
  485.     (void) SetA5(oldA5);
  486.     return(err);
  487. }
  488.  
  489. OSErr TLMSetThreadReadyGivenTaskRef(ThreadTaskRef task, ThreadID id)
  490. {
  491.     ThreadState state;
  492.     long oldA5;
  493.     OSErr err;
  494.     
  495.     oldA5 = SetA5((long) task);
  496.     err = TLMGetThreadStateGivenTaskRef(task, id, &state);
  497.     if (! err) {
  498.         if (state != kStoppedThreadState)
  499.             err = threadProtocolErr;
  500.         if (! err)
  501.             TLMSetThreadState(id, state, kNoThreadID);
  502.     }
  503.     (void) SetA5(oldA5);
  504.     return(err);
  505. }
  506.  
  507. OSErr TLMSetThreadScheduler(ThreadSchedulerProcPtr scheduler)
  508. {
  509.     OSErr err;
  510.     
  511.     ThreadProcScheduleSet(scheduler ? thread_scheduler : NULL);
  512.     err = ThreadError();
  513.     if (! err)
  514.         gThread.threadScheduler = scheduler;
  515.     return(err);
  516. }
  517.  
  518. OSErr TLMSetThreadSwitcher(ThreadID id, ThreadSwitchProcPtr switcher,
  519.         void *param, Boolean inout)
  520. {
  521.     ThreadManagerType *thread;
  522.     ThreadType sn;
  523.     OSErr err;
  524.     
  525.     err = ThreadIDToSN(id, &sn);
  526.     if (! err) {
  527.         thread = ThreadData(sn);
  528.         err = ThreadError();
  529.         if (! err) {
  530.             if (inout) {
  531.                 ThreadProcResumeSet(sn, switcher ? thread_resume : NULL);
  532.                 err = ThreadError();
  533.                 if (! err) {
  534.                     thread->switcherIn = switcher;
  535.                     thread->switcherInParam = param;
  536.                 }
  537.             }
  538.             else {
  539.                 ThreadProcSuspendSet(sn, switcher ? thread_suspend : NULL);
  540.                 err = ThreadError();
  541.                 if (! err) {
  542.                     thread->switcherOut = switcher;
  543.                     thread->switcherOutParam = param;
  544.                 }
  545.             }
  546.         }
  547.     }
  548.     return(err);
  549. }
  550.